package djinni

// -RRR | 2023-06-14 | Changes START | To generate .cpp and .hpp files for the ArkTS folder

import djinni.ast._
import djinni.generatorTools._

class ArktsHelperFilesGenerator(spec: Spec, helperFileDescriptor: ArktsHelperFilesDescriptor) extends Generator(spec) {

  def generateObjectWrapperHeader(): Unit = {

  }

  def generateHexUtilsHeader(): Unit = {
    // -RRR | 2023-07-31 | Changes START | Final modifications as per the latest changes
    // -RRR | 2023-06-19 | Changes START | Don't need the HexUtils file
    val define = ("DJINNI_GENERATED_" + spec.arktsTypePrefix + helperFileDescriptor.HexUtilsName + "_" + spec.cppHeaderExt).toUpperCase
    createFile(spec.arktsOutFolder.get, spec.arktsTypePrefix + helperFileDescriptor.HexUtilsHeader, { (w: writer.IndentWriter) =>

      w.wl("// AUTOGENERATED FILE - DO NOT MODIFY!")
      w.wl("// This file generated by Djinni")

      w.wl(s"#ifndef $define")
      w.wl(s"#define $define")
      w.wl
      w.wl("#include <memory>")
      w.wl
      w.wl("#include <string>")
      w.wl("#include <vector>")
      w.wl
      w.wl
      w.wl("namespace hex").bracedEnd(";") {
        w.wl("std::vector<uint8_t> toByteArray(const std::string &str);")
        w.wl("std::string toString(const std::vector<uint8_t>& data);")
        w.wl("uint8_t digitToByte(char c);")
        w.wl("std::string toString(const std::vector<uint8_t>& data, bool uppercase);")
        w.wl("char byteToDigit(uint8_t byte, bool uppercase);")
      }
      w.wl(s"#endif //$define")
    })
    // -RRR | 2023-06-19 | Changes END | Don't need the HexUtils file
    // -RRR | 2023-07-31 | Changes END | Final modifications as per the latest changes
  }

  def generateHexUtilsCpp(): Unit = {
    // -RRR | 2023-06-19 | Changes START | Don't need the HexUtils file
    // -RRR | 2023-07-31 | Changes START | Final modifications as per the latest changes
    createFile(spec.arktsOutFolder.get, spec.arktsTypePrefix + helperFileDescriptor.HexUtilsCpp, { (w: writer.IndentWriter) =>

      w.wl("// AUTOGENERATED FILE - DO NOT MODIFY!")
      w.wl("// This file generated by Djinni")
      w.wl("#include <stdexcept>")
      w.wl(s"""#include "${spec.arktsTypePrefix + helperFileDescriptor.HexUtilsHeader}" """)
      w.wl
      w.wl("std::vector<uint8_t> hex::toByteArray(const std::string &str)").braced {
        w.wl("std::vector<uint8_t> bytes(str.length() / 2 + str.length() % 2);")
        w.wl("auto offset = str.length() % 2 != 0 ? 1 : 0;")
        w.wl("uint8_t byte = 0;")
        w.wl("for (auto index = 0; index < bytes.size(); index++)").braced {
          w.wl("if (index == 0 && str.length() % 2 != 0)").braced {
            w.wl("byte = hex::digitToByte(str[0]);")
          }
          w.wl("else").braced {
            w.wl("byte = hex::digitToByte(str[index * 2 - offset]) << 4;")
            w.wl("byte = byte + (hex::digitToByte(str[index * 2 + 1 - offset]));")
          }
          w.wl("bytes[index] = byte;")
        }
        w.wl("return bytes;")
      }

      w.wl("uint8_t hex::digitToByte(char c)").braced {
        w.wl("if (c >= '0' && c <= '9')").braced {
          w.wl("return (uint8_t)(c - '0');")
        }
        w.wl("else if (c >= 'a' && c <= 'f')").braced {
          w.wl("return (uint8_t)(0x0A + c - 'a');")
        }
        w.wl("else if (c >= 'A' && c <= 'F')").braced {
          w.wl("return (uint8_t)(0x0A + c - 'A');")
        }
        w.wl("throw std::invalid_argument(\"Invalid hex character\");")
      }

      w.wl("std::string hex::toString(const std::vector<uint8_t>& data, bool uppercase)").braced {
        w.wl("std::string str(data.size() * 2, '0');")
        w.wl("for (auto index = 0; index < data.size(); index++)").braced {
          w.wl("str[index * 2] = byteToDigit(data[index] >> 4, uppercase);")
          w.wl("str[index * 2 + 1] = byteToDigit((uint8_t) (data[index] & 0xF), uppercase);")
        }
        w.wl("return str;")
      }

      w.wl("std::string hex::toString(const std::vector<uint8_t>& data)").braced {
        w.wl("return toString(data, false);")
      }

      w.wl("char hex::byteToDigit(uint8_t byte, bool uppercase)").braced {
        w.wl("byte = (uint8_t) (0xF < byte ? 0xF : byte);")
        w.wl("if (byte < 0xA)").braced {
          w.wl("return '0' + byte;")
        }
        w.wl("else if (uppercase)").braced {
          w.wl("return (char)('A' + (byte - 0xA));")
        }
        w.wl("else").braced {
          w.wl("return (char)('a' + (byte - 0xA));")
        }
      }
    })
    // -RRR | 2023-07-31 | Changes END | Final modifications as per the latest changes
    // -RRR | 2023-06-19 | Changes END | Don't need the HexUtils file
  }

  override def generate(idl: Seq[TypeDecl]): Unit = {
    generateObjectWrapperHeader()
    generateHexUtilsHeader()
    generateHexUtilsCpp()
  }

  override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum): Unit = ???

  override def generateRecord(origin: String, ident: Ident, doc: Doc, params: Seq[TypeParam], r: Record): Unit = ???

  override def generateInterface(origin: String, ident: Ident, doc: Doc, typeParams: Seq[TypeParam], i: Interface): Unit = ???
}

// -RRR | 2023-06-14 | Changes END | To generate .cpp and .hpp files for the ArkTS folder